package com.mobile.service.statemachine;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.mobile.service.entity.InsuranceApproval;
import com.mobile.service.entity.ProcessFlow;
import com.mobile.service.entity.SupplementInfo;
import com.mobile.service.entity.WorkOrder;
import com.mobile.service.enums.WorkOrderEvent;
import com.mobile.service.enums.WorkOrderStatus;
import com.mobile.service.impl.DocumentGenerationService;
import com.mobile.service.inter.*;
import com.mobile.service.inter.system.UserService;
import com.mobile.service.mapper.SupplementInfoMapper;
import com.mobile.util.PageData;
import com.mobile.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;

/**
 * 工单状态机组件
 */
@Slf4j
@Component
public class WorkOrderStateMachine {

    @Autowired
    private WorkOrderService workOrderService;
    
    @Autowired
    private ProcessFlowService processFlowService;
    
    @Autowired
    private InsuranceApprovalService insuranceApprovalService;

    @Autowired
    private SupplementInfoMapper supplementInfoMapper;

    @Autowired
    private BusinessDocumentService businessDocumentService;
    
    @Autowired
    private UserService userService;

    // 定义状态流转规则
    private static final Map<WorkOrderStatus, Set<WorkOrderEvent>> STATE_TRANSITIONS = new HashMap<>();
    
    static {
        log.info("初始化工单状态机流转规则");
        
        // SUBMITTED 状态可以流转的事件
        STATE_TRANSITIONS.put(WorkOrderStatus.SUBMITTED, Collections.singleton(WorkOrderEvent.SUBMIT_AUDIT));
        log.debug("配置SUBMITTED状态流转规则: {}", WorkOrderEvent.SUBMIT_AUDIT);
        
        // RE_DISPATCH 状态可以流转的事件
        STATE_TRANSITIONS.put(WorkOrderStatus.RE_DISPATCH, Collections.singleton(WorkOrderEvent.ENTER_AUDIT));
        log.debug("配置RE_DISPATCH状态流转规则: {}", WorkOrderEvent.ENTER_AUDIT);
        
        // AUDITING 状态可以流转的事件
        Set<WorkOrderEvent> auditingEvents = new HashSet<>();
        auditingEvents.add(WorkOrderEvent.COMPLETE_AUDIT);
        auditingEvents.add(WorkOrderEvent.NEED_CORRECTION);
        auditingEvents.add(WorkOrderEvent.NEED_COLLABORATION);
        auditingEvents.add(WorkOrderEvent.REJECT_AUDIT);
        auditingEvents.add(WorkOrderEvent.NEED_REDISPATCH);
        STATE_TRANSITIONS.put(WorkOrderStatus.AUDITING, Collections.unmodifiableSet(auditingEvents));
        log.debug("配置AUDITING状态流转规则: {}", auditingEvents);
        
        // NEED_CORRECT 状态可以流转的事件
        STATE_TRANSITIONS.put(WorkOrderStatus.NEED_CORRECT, Collections.singleton(WorkOrderEvent.COMPLETE_CORRECTION));
        log.debug("配置NEED_CORRECT状态流转规则: {}", WorkOrderEvent.COMPLETE_CORRECTION);
        
        // COLLABORATING 状态可以流转的事件
        Set<WorkOrderEvent> collaboratingEvents = new HashSet<>();
        collaboratingEvents.add(WorkOrderEvent.COMPLETE_COLLABORATION);
        collaboratingEvents.add(WorkOrderEvent.COLLABORATION_NEED_CORRECTION);
        STATE_TRANSITIONS.put(WorkOrderStatus.COLLABORATING, Collections.unmodifiableSet(collaboratingEvents));
        log.debug("配置COLLABORATING状态流转规则: {}", collaboratingEvents);
        
        log.info("工单状态机流转规则初始化完成，共配置{}种状态", STATE_TRANSITIONS.size());
    }

    /**
     * 执行状态流转
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> executeTransition(Integer workOrderId, WorkOrderEvent event, WorkOrderStateContext context) {
        log.info("开始执行工单状态流转 - 工单ID: {}, 事件: {}, 操作用户: {}", 
                workOrderId, event, context.getCurrentUser());
        
        try {
            // 1. 获取当前工单信息
            log.debug("步骤1: 获取工单信息 - 工单ID: {}", workOrderId);
            WorkOrder workOrder = getWorkOrderEntity(workOrderId);
            if (workOrder == null) {
                String errorMsg = "工单不存在，工单ID: " + workOrderId;
                log.error(errorMsg);
                return Result.error(errorMsg);
            }
            log.info("成功获取工单信息 - 工单ID: {}, 当前状态: {}", workOrderId, workOrder.allocationStatus());

            WorkOrderStatus currentStatus = WorkOrderStatus.fromCode(workOrder.allocationStatus());
            
            // 2. 验证状态流转是否合法
            log.debug("步骤2: 验证状态流转合法性 - 当前状态: {}, 目标事件: {}", currentStatus, event);
            if (!isValidTransition(currentStatus, event)) {
                String errorMsg = String.format("非法的状态流转 - 当前状态: %s, 事件: %s, 工单ID: %s", 
                        currentStatus, event, workOrderId);
                log.error(errorMsg);
                return Result.error(errorMsg);
            }
            log.info("状态流转验证通过 - 当前状态: {}, 事件: {}", currentStatus, event);

            // 3. 计算目标状态
            log.debug("步骤3: 计算目标状态 - 当前状态: {}, 事件: {}", currentStatus, event);
            WorkOrderStatus targetStatus = calculateTargetStatus(currentStatus, event);
            log.info("计算目标状态完成 - 当前状态: {} -> 目标状态: {}", currentStatus, targetStatus);
            
            // 4. 更新工单状态
            log.debug("步骤4: 更新工单状态 - 工单ID: {}, 目标状态: {}", workOrderId, targetStatus);
            updateWorkOrderStatus(workOrder, targetStatus, context);
            log.info("工单状态更新成功 - 工单ID: {}, 新状态: {}", workOrderId, targetStatus);
            
            // 5. 新增流程记录
            log.debug("步骤5: 创建流程记录 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);
            createProcessFlowRecord(workOrder, targetStatus, context);
            log.info("流程记录创建成功 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);

            if (targetStatus == WorkOrderStatus.NEED_CORRECT){
                createSupplementInfoRecord(workOrder, context);
                log.info("补正信息创建成功 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);
            }

            // 6. 新增保险审核记录
            log.debug("步骤6: 创建保险审核记录 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);
            createInsuranceApprovalRecord(workOrder, targetStatus, context);
            log.info("保险审核记录创建成功 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);

            //7. 创建结果文书 审批通过和拒绝
            if (targetStatus == WorkOrderStatus.COMPLETED || targetStatus == WorkOrderStatus.REJECTED){
                log.debug("步骤7: 创建结果文书 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);
                createResultDocument(workOrder);
                log.info("结果文书创建成功 - 工单ID: {}, 状态: {}", workOrderId, targetStatus);
            }

            log.info("工单状态流转成功完成 - 工单ID: {}, 状态变更: {} -> {}, 操作用户: {}", 
                    workOrderId, currentStatus, targetStatus, context.getCurrentUser());
            return Result.success("工单状态流转成功", true);
            
        } catch (Exception e) {
            String errorMsg = String.format("工单状态流转失败 - 工单ID: %s, 事件: %s, 操作用户: %s, 错误信息: %s", 
                    workOrderId, event, context.getCurrentUser(), e.getMessage());
            log.error(errorMsg, e);
            return Result.error(errorMsg);
        }
    }

    private void createResultDocument(WorkOrder workOrder) {
        businessDocumentService.generateAndSaveBusinessDocument(workOrder.workOrderId());
    }

    private void createSupplementInfoRecord(WorkOrder workOrder,WorkOrderStateContext context) {

        SupplementInfo supplementInfo = new SupplementInfo();
        supplementInfo.insuranceType(workOrder.insuranceType());
        supplementInfo.applicationFormId(workOrder.applicationFormId());
        supplementInfo.supplementContent(context.getReviewComment());
        supplementInfo.staffId(context.getCurrentUser());
        supplementInfo.status("0");
        supplementInfo.dueDate(LocalDate.now().plusDays(3));
        supplementInfo.applicantId(workOrder.applicantId());
        supplementInfo.createUser(context.getCurrentUser());
        supplementInfo.updateUser(context.getCurrentUser());
        supplementInfoMapper.insertSupplementInfo(supplementInfo);
    }

    /**
     * 验证状态流转是否合法
     */
    private boolean isValidTransition(WorkOrderStatus currentStatus, WorkOrderEvent event) {
        log.debug("验证状态流转合法性 - 当前状态: {}, 事件: {}", currentStatus, event);
        
        Set<WorkOrderEvent> allowedEvents = STATE_TRANSITIONS.get(currentStatus);
        if (allowedEvents == null) {
            log.warn("当前状态没有配置允许的事件 - 状态: {}", currentStatus);
            return false;
        }
        
        boolean isValid = allowedEvents.contains(event);
        log.debug("状态流转验证结果 - 当前状态: {}, 事件: {}, 是否合法: {}, 允许的事件: {}", 
                currentStatus, event, isValid, allowedEvents);
        
        return isValid;
    }

    /**
     * 计算目标状态
     */
    private WorkOrderStatus calculateTargetStatus(WorkOrderStatus currentStatus, WorkOrderEvent event) {
        log.debug("计算目标状态 - 当前状态: {}, 事件: {}", currentStatus, event);
        
        WorkOrderStatus targetStatus;
        switch (event) {
            case SUBMIT_AUDIT:
            case ENTER_AUDIT:
            case COMPLETE_CORRECTION:
            case COMPLETE_COLLABORATION:
                targetStatus = WorkOrderStatus.AUDITING;
                log.debug("事件 {} 对应目标状态: {}", event, targetStatus);
                break;
            case COMPLETE_AUDIT:
                targetStatus = WorkOrderStatus.COMPLETED;
                log.debug("事件 {} 对应目标状态: {}", event, targetStatus);
                break;
            case NEED_CORRECTION:
            case COLLABORATION_NEED_CORRECTION:
                targetStatus = WorkOrderStatus.NEED_CORRECT;
                log.debug("事件 {} 对应目标状态: {}", event, targetStatus);
                break;
            case NEED_COLLABORATION:
                targetStatus = WorkOrderStatus.COLLABORATING;
                log.debug("事件 {} 对应目标状态: {}", event, targetStatus);
                break;
            case REJECT_AUDIT:
                targetStatus = WorkOrderStatus.REJECTED;
                log.debug("事件 {} 对应目标状态: {}", event, targetStatus);
                break;
            case NEED_REDISPATCH:
                targetStatus = WorkOrderStatus.RE_DISPATCH;
                log.debug("事件 {} 对应目标状态: {}", event, targetStatus);
                break;
            default:
                log.error("未知的事件类型: {}", event);
                throw new IllegalArgumentException("未知的事件类型: " + event);
        }
        
        log.info("目标状态计算完成 - 当前状态: {}, 事件: {}, 目标状态: {}", currentStatus, event, targetStatus);
        return targetStatus;
    }

    /**
     * 更新工单状态
     */
    private void updateWorkOrderStatus(WorkOrder workOrder, WorkOrderStatus targetStatus, WorkOrderStateContext context) throws Exception {
        log.debug("开始更新工单状态 - 工单ID: {}, 目标状态: {}", workOrder.workOrderId(), targetStatus);
        
        String originalStatus = workOrder.allocationStatus();
        workOrder.allocationStatus(targetStatus.getCode());
        workOrder.updateUser(context.getCurrentUser());
        workOrder.updateDatetime(new Date());
        
        // 根据状态更新相关字段
        if (context.getProcessorId() != null) {
            log.debug("更新处理人员ID: {} -> {}", workOrder.handlingStaffId(), context.getProcessorId());
            workOrder.handlingStaffId(context.getProcessorId()); // 现在都是 String 类型，无需转换
        }
        if (context.getAllocationReason() != null) {
            log.debug("更新分配原因: {}", context.getAllocationReason());
            workOrder.allocationReason(context.getAllocationReason());
        }
        if (context.getDispatchType() != null) {
            log.debug("更新调度类型: {}", context.getDispatchType());
            workOrder.dispatchType(context.getDispatchType());
        }
        
        workOrderService.updateWorkOrder(workOrder);
        log.info("工单状态更新完成 - 工单ID: {}, 状态变更: {} -> {}, 操作用户: {}", 
                workOrder.workOrderId(), originalStatus, targetStatus.getCode(), context.getCurrentUser());
    }

    /**
     * 创建流程记录
     */
    private void createProcessFlowRecord(WorkOrder workOrder, WorkOrderStatus targetStatus, WorkOrderStateContext context) throws Exception {
        log.debug("开始创建流程记录 - 工单ID: {}, 状态: {}", workOrder.workOrderId(), targetStatus);
        
        ProcessFlow processFlow = new ProcessFlow();
        processFlow.workOrderId(workOrder.workOrderId());
        processFlow.currentReviewStatus(targetStatus.getCode());
        processFlow.applicantId(workOrder.applicantId());
        processFlow.processorId(context.getCurrentUser());
        processFlow.dispatcherId(context.getCurrentUser());
        processFlow.dispatchType("手动派工");
        processFlow.estimatedReviewDuration(context.getEstimatedReviewDuration());
        processFlow.reviewTime(new Date());
        processFlow.createUser(context.getCurrentUser());
        processFlow.createDatetime(new Date());
        processFlow.updateUser(context.getCurrentUser());
        processFlow.updateDatetime(new Date());
        
        log.debug("流程记录详情 - 工单ID: {}, 审核状态: {}, 申请人ID: {}, 处理人ID: {}, 调度员ID: {}", 
                processFlow.workOrderId(), processFlow.currentReviewStatus(), 
                processFlow.applicantId(), processFlow.processorId(), processFlow.dispatcherId());
        
        processFlowService.insertProcessFlow(processFlow);
        log.info("流程记录创建成功 - 工单ID: {}, 状态: {}, 操作用户: {}", 
                workOrder.workOrderId(), targetStatus, context.getCurrentUser());
    }

    /**
     * 创建保险审核记录
     */
    private void createInsuranceApprovalRecord(WorkOrder workOrder, WorkOrderStatus targetStatus, WorkOrderStateContext context) throws Exception {
        log.debug("开始创建保险审核记录 - 工单ID: {}, 保险类型: {}, 状态: {}", 
                workOrder.workOrderId(), workOrder.insuranceType(), targetStatus);
        
        // 根据当前用户代码获取用户信息
        String userCode = context.getCurrentUser();
        PageData userData = userService.getUserByCode(userCode);
        
        String auditorName = "";
        String department = "";
        
        if (userData != null) {
            auditorName = userData.getString("user_name");
            department = userData.getString("organization_name");
            log.debug("获取用户信息成功 - 用户代码: {}, 用户名称: {}, 部门: {}", userCode, auditorName, department);
        } else {
            log.warn("未找到用户信息 - 用户代码: {}", userCode);
            auditorName = userCode; // 如果找不到用户信息，使用用户代码作为审核人姓名
        }
        
        InsuranceApproval approval = new InsuranceApproval();
        approval.insuranceType(workOrder.insuranceType());
        approval.declarationId(workOrder.applicantId()); // 已经是 String 类型，无需转换
        approval.approvalStatus(targetStatus.getCode());
        approval.reviewComment(context.getReviewComment());
        approval.reviewedAt(new Date());
        approval.auditorName(auditorName); // 设置审核人姓名
        approval.department(department); // 设置审核人部门
        approval.createUser(context.getCurrentUser());
        approval.createDatetime(new Date());
        approval.updateUser(context.getCurrentUser());
        approval.updateDatetime(new Date());
        
        log.debug("保险审核记录详情 - 保险类型: {}, 申报ID: {}, 审核状态: {}, 审核人姓名: {}, 审核人部门: {}, 审核意见: {}", 
                approval.insuranceType(), approval.declarationId(), 
                approval.approvalStatus(), approval.auditorName(), approval.department(), approval.reviewComment());
        
        insuranceApprovalService.insertInsuranceApproval(approval);
        log.info("保险审核记录创建成功 - 工单ID: {}, 保险类型: {}, 状态: {}, 审核人: {}, 部门: {}, 操作用户: {}", 
                workOrder.workOrderId(), workOrder.insuranceType(), targetStatus, auditorName, department, context.getCurrentUser());
    }


    /**
     * 获取工单实体
     */
    private WorkOrder getWorkOrderEntity(Integer workOrderId) throws Exception {
        log.debug("获取工单实体 - 工单ID: {}", workOrderId);
        
        try {
            WorkOrder workOrder = workOrderService.getWorkOrderEntityById(workOrderId);
            if (workOrder != null) {
                log.debug("成功获取工单实体 - 工单ID: {}, 工单号: {}, 当前状态: {}", 
                        workOrderId, workOrder.workOrderNo(), workOrder.allocationStatus());
            } else {
                log.warn("工单实体不存在 - 工单ID: {}", workOrderId);
            }
            return workOrder;
        } catch (Exception e) {
            log.error("获取工单实体失败 - 工单ID: {}, 错误信息: {}", workOrderId, e.getMessage(), e);
            throw e;
        }
    }
}